use hypers::prelude::*;
use hypers::tokio;
use serde::{Deserialize, Serialize};
use validator::Validate;

// 通过 validator 这个 库的 Validate 宏在 User 这个结构体上定义参数验证规则
#[derive(Serialize, Deserialize, Validate, Extract, Default, Debug, PartialEq)]
pub struct User {
    #[validate(email)]
    pub email: String, // admin@outlook.com
    #[validate(range(min = 18, max = 20))]
    pub age: u16,
}

struct Api;
#[controller]
impl Api {
    #[post("/register",validate = [User])] // 在这里将 User 这个类型注册到 当前这个请求中，请求会自动验证参数
    async fn register(user: User) -> impl Responder {
        (200, Json(user))
    }
}

fn route() -> Router {
    Api.into()
}

async fn start_server() -> Result<()> {
    let listener = hypers::TcpListener::bind("127.0.0.1:7878").await?;
    hypers::listen(route(), listener).await
}

#[tokio::main]
async fn main() -> Result<()> {
    start_server().await
}

mod test {
    use super::*;

    #[allow(unused_must_use)]
    #[tokio::test]
    async fn test() {
        tokio::task::spawn(async {
            let _ = start_server().await;
        });
        tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
        let mut user = User {
            email: "1123afc@163.com".to_owned(),
            age: 18,
        };
        let cli = hypers::TestClient::new(route());
        let mut res = cli
            .post("http://127.0.0.1:7878/register")
            .json(&user)
            .send()
            .await;
        res.assert_status_is_ok();
        res.assert_json(&user);

        user.age = 15;
        let mut res = cli
            .post("http://127.0.0.1:7878/register")
            .json(&user)
            .send()
            .await;
        res.assert_status(400);
        println!("response body {}", res.take_string().await.unwrap());
    }
}
